/**************************************************************************
 *  Copyright (C) 2008 - 2010 by Simon Qian                               *
 *  SimonQian@SimonQian.com                                               *
 *                                                                        *
 *  Project:    Versaloon                                                 *
 *  File:       GPIO.h                                                    *
 *  Author:     SimonQian                                                 *
 *  Versaion:   See changelog                                             *
 *  Purpose:    GPIO interface header file                                *
 *  License:    See license                                               *
 *------------------------------------------------------------------------*
 *  Change Log:                                                           *
 *      YYYY-MM-DD:     What(by Who)                                      *
 *      2008-11-07:     created(by SimonQian)                             *
 **************************************************************************/
#include "vsf.h"

struct w600_gpio_reg_t
{
	uint32_t DATA;
	uint32_t DATA_EN;
	uint32_t DATA_DIR;		// 1 for output, 0 for input
	uint32_t DATA_PULLEN;	// 1 for disable, 0 for enable
	uint32_t AFSEL;
	uint32_t AFS1;
	uint32_t AFS0;
	uint32_t dummy;
	uint32_t IS;
	uint32_t IBE;
	uint32_t IEV;
	uint32_t IE;
	uint32_t RIS;
	uint32_t MIS;
	uint32_t IC;
};

#define VSFHAL_GPIO_NUM					2

#define W600_REGCFG_GPIO(base)		\
	{.reg = (struct w600_gpio_reg_t *)(base),}
struct w600_gpio_t
{
	volatile struct w600_gpio_reg_t *reg;
} const vsfhal_gpio[VSFHAL_GPIO_NUM] =
{
	W600_REGCFG_GPIO(HR_GPIOA_BASE_ADDR),
	W600_REGCFG_GPIO(HR_GPIOB_BASE_ADDR),
};

vsf_err_t vsfhal_gpio_afsel(uint8_t port, uint8_t pin, uint8_t afsel, uint8_t pull)
{
	uint32_t pin_mask = 1 << pin;
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[port].reg;
	if (port >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;

	reg->AFSEL |= pin_mask;
	(afsel & (1 << 0)) ? (reg->AFS0 |= pin_mask) : (reg->AFS0 &= ~pin_mask);
	(afsel & (1 << 1)) ? (reg->AFS1 |= pin_mask) : (reg->AFS1 &= ~pin_mask);
	pull ? (reg->DATA_PULLEN |= pin_mask) : (reg->DATA_PULLEN &= ~pin_mask);
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_init(uint8_t index)
{
	return index >= dimof(vsfhal_gpio) ? VSFERR_NOT_SUPPORT : VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_fini(uint8_t index)
{
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_config(uint8_t index, uint8_t pin_idx, uint32_t mode)
{
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[index].reg;
	if (index >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;
	uint32_t pin_mask = 1 << pin_idx;

	reg->AFSEL &= ~pin_mask;
	(mode & (1 << 0)) ? (reg->DATA_DIR |= pin_mask) : (reg->DATA_DIR &= ~pin_mask);
	(mode & (1 << 1)) ? (reg->DATA_PULLEN |= pin_mask) : (reg->DATA_PULLEN &= ~pin_mask);
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_set(uint8_t index, uint32_t pin_mask)
{
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[index].reg;
	if (index >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;

	uint32_t gpio_en = reg->DATA_EN;
	reg->DATA_EN |= pin_mask;
	reg->DATA |= pin_mask;
	reg->DATA_EN = gpio_en;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_clear(uint8_t index, uint32_t pin_mask)
{
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[index].reg;
	if (index >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;

	uint32_t gpio_en = reg->DATA_EN;
	reg->DATA_EN |= pin_mask;
	reg->DATA &= ~pin_mask;
	reg->DATA_EN = gpio_en;
	return VSFERR_NONE;
}

vsf_err_t vsfhal_gpio_out(uint8_t index, uint32_t pin_mask, uint32_t value)
{
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[index].reg;
	if (index >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;

	uint32_t gpio_en = reg->DATA_EN;
	reg->DATA_EN |= pin_mask;
	reg->DATA |= pin_mask & value;
	reg->DATA &= ~(pin_mask & ~value);
	reg->DATA_EN = gpio_en;
	return VSFERR_NONE;
}

uint32_t vsfhal_gpio_get(uint8_t index, uint32_t pin_mask)
{
	volatile struct w600_gpio_reg_t *reg = vsfhal_gpio[index].reg;
	if (index >= dimof(vsfhal_gpio)) return VSFERR_NOT_SUPPORT;

	uint32_t gpio_en = reg->DATA_EN;
	reg->DATA_EN |= pin_mask;
	uint32_t gpio = reg->DATA;
	reg->DATA_EN = gpio_en;
	return gpio & pin_mask;
}
